// $Id: Enumerable.java 48 2012-11-25 23:18:34Z marcel.kloubert $

/*****************************************************************************
 *                                                                           *
 *   Licensed to the Apache Software Foundation (ASF) under one              *
 *   or more contributor license agreements.  See the NOTICE file            *
 *   distributed with this work for additional information                   *
 *   regarding copyright ownership.  The ASF licenses this file              *
 *   to you under the Apache License, Version 2.0 (the                       *
 *   "License"); you may not use this file except in compliance              *
 *   with the License.  You may obtain a copy of the License at              *
 *                                                                           *
 *       http://www.apache.org/licenses/LICENSE-2.0                          *
 *                                                                           *
 *   Unless required by applicable law or agreed to in writing,              *
 *   software distributed under the License is distributed on an             *
 *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY                  *
 *   KIND, either express or implied.  See the License for the               *
 *   specific language governing permissions and limitations                 *
 *   under the License.                                                      *
 *                                                                           *
 *****************************************************************************/


package net.metalvz.linq;

import java.util.ArrayList;
import java.util.Map;

/**
 * Helper class for list / sequence operations.
 * 
 * @author Marcel Joachim Kloubert <marcel.kloubert@gmx.net>
 */
public final class Enumerable {
	private Enumerable() {
		
	}
	
	/**
	 * Returns an iterable as sequence. 
	 * 
	 * @param seq The iterable.
	 * @param <T> Type of the items.
	 * 
	 * @return The iterable as sequence.
	 */
	public static <T> IEnumerable<T> asEnumerable(Iterable<T> seq) {
		if (seq instanceof IEnumerable<?>) {
			// simple cast
			return (IEnumerable<T>)seq;
		}
		else {
			return new IterableEnumerable<T>(seq);
		}
	}	
	
	//TODO: implement
	/* @SuppressWarnings("unchecked")
	public static <T> T[] toArray(Iterable<T> seq) {
		ArrayList<T> temp = new ArrayList<T>();
		for (T item: seq) {
			temp.add(item);
		}
		
		return (T[])temp.toArray();
	}*/
	
	/**
	 * Returns an empty sequence.
	 * 
	 * @return The sequence with the created items.
	 */
	public static <T> IEnumerable<T> empty() {
		return asEnumerable(new ArrayList<T>());
	}
	
	/**
	 * Creates a range of integer values.
	 * 
	 * @param start The start value.
	 * @param count The number of values.
	 * 
	 * @return The created sequence.
	 * 
	 * @throws IllegalArgumentException count is smaller than 0 -or-
	 *                                  start + count -1 > Integer.MAX_VALUE
	 */
	public static IEnumerable<Integer> range(int start, int count) throws IllegalArgumentException {
		if (count < 0) {
			throw new IllegalArgumentException("count must be at least 0!");
		}
		
		if ((start + count - 1) > Integer.MAX_VALUE) {
			throw new IllegalArgumentException("start+count are out of range!");
		}
		
		Integer[] result = new Integer[count];
		for (int i = 0; i < count; i++) {
			result[i] = start + i;
		}
		
		return toEnumerable(result);
	}
	
	/**
	 * Repeats an object and returns it as sequence.
	 * 
	 * @param item The item to repeat.
	 * @param count The number of items to repeat.
	 * 
	 * @return The sequence with the created items.
	 * 
	 * @throws IllegalArgumentException count is smaller than 0.
	 */
	public static <T> IEnumerable<T> repeat(T item, int count) throws IllegalArgumentException {
		if (count < 0) {
			throw new IllegalArgumentException("count must be at least 0!");
		}
		
		ArrayList<T> temp = new ArrayList<T>();
		for (int i = 0; i < count; i++) {
			temp.add(item);
		}
		
		return asEnumerable(temp);
	}
	
	/**
	 * Returns an array as sequence. 
	 * 
	 * @param array The array.
	 * @param <T> Type of the items.
	 * 
	 * @return The array as sequence.
	 */
	public static <T> IEnumerable<T> toEnumerable(T[] array) {
		return new ArrayEnumerable<T>(array);
	}
	
	/**
	 * Converts a map to a sequence.
	 * 
	 * @param map The map.
	 * @param <K> Type of the keys.
	 * @param <T> Type of the items.
	 * 
	 * @return The map as sequence.
	 */
	public static <K, T> IEnumerable<Map.Entry<K, T>> toEnumerable(Map<K, T> map) {
		return asEnumerable(map.entrySet());
	}
}
